package com.ktg.mes.wm.service.impl;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ktg.common.utils.DateUtils;
import com.ktg.common.utils.SecurityUtils;
import com.ktg.common.utils.StringUtils;
import com.ktg.mes.chanjet.content.InventoryClassContent;
import com.ktg.mes.chanjet.response.InventoryClassResponse;
import com.ktg.mes.chanjet.spi.ChanjetSpi;
import com.ktg.mes.md.domain.MdItem;
import com.ktg.mes.md.service.IMdItemService;
import com.ktg.mes.md.service.IMdProductStatisticsBomService;
import com.ktg.mes.pro.domain.ProItemNeed;
import com.ktg.mes.pro.domain.ProTask;
import com.ktg.mes.pro.domain.ProWorkorder;
import com.ktg.mes.pro.service.IProTaskService;
import com.ktg.mes.pro.service.IProWorkorderService;
import com.ktg.mes.unit.other.SQLListenerInterface;
import com.ktg.mes.unit.other.SQLListenerType;
import com.ktg.mes.unit.other.ZLServiceIml;
import com.ktg.mes.unit.sql.service.SQLToolService;
import com.ktg.mes.unit.sync.SyncModel;
import com.ktg.mes.unit.sync.service.IFromService;
import com.ktg.mes.util.LGLeftJoinQueryWrapper;
import com.ktg.common.core.domain.model.SqlResult;
import com.ktg.mes.webSocket.NoticeWbsocketType;
import com.ktg.mes.webSocket.NoticeWebsocket;
import com.ktg.mes.wm.domain.*;
import com.ktg.mes.wm.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ktg.mes.wm.mapper.WmItemRecptLineMapper;

/**
 * 物料入库单行Service业务层处理
 *
 * @author yinjinlu
 * @date 2022-05-22
 */
@Service
public class WmItemRecptLineServiceImpl extends ZLServiceIml<WmItemRecptLineMapper, WmItemRecptLine> implements IWmItemRecptLineService
{


    @Autowired
    private IFromService fromService;

    @Autowired
    private SQLToolService toIService;

    @Autowired
    private IWmMaterialStockService wmMaterialStockService;

    @Autowired
    private IWmWarehouseService wmWarehouseService;

    @Autowired
    private IMdItemService mdItemService;

    @Autowired
    private IProTaskService proTaskService;

    @Autowired
    private IProWorkorderService proWorkorderService;

    @Autowired
    private IWmItemRecptLineService wmItemRecptLineService;


    @Autowired
    private ChanjetSpi chanjetSpi;




    /**
     * 查询物料入库单行
     *
     * @param lineId 物料入库单行主键
     * @return 物料入库单行
     */
    @Override
    public WmItemRecptLine selectWmItemRecptLineByLineId(Long lineId)
    {
        return getBaseMapper().selectWmItemRecptLineByLineId(lineId);
    }

    /**
     * 查询物料入库单行列表
     *
     * @param wmItemRecptLine 物料入库单行
     * @return 物料入库单行
     */
    @Override
    public List<WmItemRecptLine> selectWmItemRecptLineList(WmItemRecptLine wmItemRecptLine)
    {
        return getBaseMapper().selectWmItemRecptLineList(wmItemRecptLine);
    }

    /**
     * 新增物料入库单行
     *
     * @param wmItemRecptLine 物料入库单行
     * @return 结果
     */
    public SqlResult insertWmItemRecptLine(WmItemRecptLine wmItemRecptLine)
    {
        wmItemRecptLine.setCreateBy(SecurityUtils.getUsername());
        wmItemRecptLine.setCreateTime(DateUtils.getNowDate());
        return insertSQLModel(wmItemRecptLine);
    }

    public void initQuantity(WmItemRecptLine wmItemRecptLine){
        //统计库存数据
        float aa = 0;
        if (wmItemRecptLine.getQuantityOut() != null){
            aa = wmItemRecptLine.getQuantityOut().floatValue();
        }
        aa = wmItemRecptLine.getQuantityRecived().floatValue()-aa;
        wmItemRecptLine.setQuantity(BigDecimal.valueOf(aa));
    }


    /**
     * 批量删除物料入库单行
     *
     * @param lineIds 需要删除的物料入库单行主键
     * @return 结果
     */
    @Override
    public SqlResult deleteWmItemRecptLineByLineIds(Long[] lineIds)
    {
        return deleteSQLIds(lineIds);
    }

    /**
     * 删除物料入库单行信息
     *
     * @param lineId 物料入库单行主键
     * @return 结果
     */
    @Override
    public SqlResult deleteWmItemRecptLineByLineId(Long lineId)
    {
        return deleteSQLId(lineId);
    }

    @Override
    public SqlResult deleteByRecptId(Long recptId) {
        QueryWrapper<WmItemRecptLine> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("recpt_id",recptId);
        return deleteSQLModelList(list(queryWrapper));
    }

    /**
     * 查询排产任务taskId 已入库数量,排产数量
     * @param taskId
     * @return
     */
    public List<JSONObject> findTaskQuantityAndItemRecptLineQuantity(WmItemRecptLine line){
        List<JSONObject> list = getBaseMapper().findTaskQuantityAndItemRecptLineQuantity(line);
        return list;
    }


    /**
     * 通过生产退料检测一条入库信息
     * @param issueLine
     */
    public  WmItemRecptLine createRecptLineFromWmRtIssueLine(WmRtIssueLine issueLine){
        if (issueLine == null){
            return null;
        }

        WmItemRecptLine old = wmItemRecptLineService.getById(issueLine.getItemRecptLineId());

        WmItemRecptLine itemRecptLine = new WmItemRecptLine();
        itemRecptLine.setCreateBy(SecurityUtils.getUsername());
        itemRecptLine.setCreateTime(new Date());
        itemRecptLine.setItemId(issueLine.getItemId());
        itemRecptLine.setItemCode(issueLine.getItemCode());
        itemRecptLine.setItemName(issueLine.getItemName());
        itemRecptLine.setViscosity(old.getViscosity());
        itemRecptLine.setSpecification(issueLine.getSpecification());
        itemRecptLine.setMeterialCode(issueLine.getMeterialCode());
        itemRecptLine.setPackingType(old.getPackingType());
        itemRecptLine.setTag(old.getTag());
        itemRecptLine.setExpireDate(old.getExpireDate());
        itemRecptLine.setItemCode(issueLine.getItemCode());

        itemRecptLine.setInType(old.getInType());
        itemRecptLine.setBatchCode(old.getBatchCode());

        itemRecptLine.setWarehouseId(issueLine.getWarehouseId());
        itemRecptLine.setWarehouseCode(issueLine.getWarehouseCode());
        itemRecptLine.setWarehouseName(issueLine.getWarehouseName());

        itemRecptLine.setStatus(issueLine.getLetStepMaterial());
        itemRecptLine.setLetStepMaterial(issueLine.getLetStepMaterial());
        itemRecptLine.setQuantityOut(BigDecimal.valueOf(0));
        itemRecptLine.setQuantityRecived(issueLine.getQuantityRt());
        itemRecptLine.setRemark("生产退料");
        itemRecptLine.setAttr1(String.valueOf(issueLine.getLineId()));
        itemRecptLine.setIsInStock("1");

        addWmItemRecptLine(itemRecptLine);
        return itemRecptLine;
    }



    /**
     *
     * @param wmItemRecptLine
     * @return
     */
    public SqlResult addWmItemRecptLine(WmItemRecptLine wmItemRecptLine){
        WmWarehouse warehouse = null;
        //补全仓库
        if(StringUtils.isNotNull(wmItemRecptLine.getWarehouseId())
                && (StringUtils.isEmpty(wmItemRecptLine.getWarehouseCode())  || StringUtils.isEmpty(wmItemRecptLine.getWarehouseName()))){
            warehouse = wmWarehouseService.selectWmWarehouseByWarehouseId(wmItemRecptLine.getWarehouseId());
            wmItemRecptLine.setWarehouseCode(warehouse.getWarehouseCode());
            wmItemRecptLine.setWarehouseName(warehouse.getWarehouseName());

            if (warehouse == null){
                return SqlResult.error("仓库不能为空",null);
            }
        }

        //调整入库类型,3是组装入库
        if ("3".equals(wmItemRecptLine.getInType()) && StringUtils.isEmpty(wmItemRecptLine.getIsInStock())){
            wmItemRecptLine.setIsInStock("0");
        }else {
            wmItemRecptLine.setIsInStock("1");
        }

        //默认入库为0
        if (StringUtils.isEmpty(wmItemRecptLine.getStatus())){
            wmItemRecptLine.setStatus("0");
        }
        if (wmItemRecptLine.getQuantityOut() == null){
            wmItemRecptLine.setQuantityOut(BigDecimal.valueOf(0));
        };

        //修改入库排产的状态
        if (wmItemRecptLine.getTaskId() != null && wmItemRecptLine.getTaskId() > 0 && !"0".equals(wmItemRecptLine.getIsInStock())){
            ProTask proTask = proTaskService.getById(wmItemRecptLine.getTaskId());
            //如果是排产入库，判断入库数量，防止排产数量不足预出库
            SqlResult result = wmItemRecptLineService.inPutRelationProstaskAndWillOut(wmItemRecptLine,proTask);
            if (result.getCode() != 0){
                return result;
            }
        }


        MdItem mdItem = mdItemService.getById(wmItemRecptLine.getItemId());
        if (wmItemRecptLine.getExpireDate() == null){
            ProWorkorder workorder = proWorkorderService.getById(wmItemRecptLine.getWorkorderId());
            if (workorder != null && workorder.getTagDate() != null){
                wmItemRecptLine.setExpireDate(DateUtils.dateByAddMonth(workorder.getTagDate(),mdItem.getValidTerm()!=null? mdItem.getValidTerm():6));
            }
        }
        initQuantity(wmItemRecptLine);

        return insertWmItemRecptLine(wmItemRecptLine);
    }


    /**
     * 修改物料入库单行
     *
     * @param wmItemRecptLine 物料入库单行
     * @return 结果
     */
    @Override
    public SqlResult updateWmItemRecptLine(WmItemRecptLine wmItemRecptLine)
    {

        WmWarehouse warehouse = null;
        if(StringUtils.isNotNull(wmItemRecptLine.getWarehouseId())){
            warehouse = wmWarehouseService.selectWmWarehouseByWarehouseId(wmItemRecptLine.getWarehouseId());
            wmItemRecptLine.setWarehouseCode(warehouse.getWarehouseCode());
            wmItemRecptLine.setWarehouseName(warehouse.getWarehouseName());
        }
        if (warehouse == null){
            return SqlResult.error("仓库不能为空",null);
        }

        if (wmItemRecptLine.getTaskId() != null && wmItemRecptLine.getTaskId() > 0){
            SqlResult result = wmItemRecptLineService.inPutRelationProstaskAndWillOut(wmItemRecptLine,null);
            if (result.getCode() != 0){
                return result;
            }
        }

        initQuantity(wmItemRecptLine);
        wmItemRecptLine.setUpdateBy(SecurityUtils.getUsername());
        wmItemRecptLine.setUpdateTime(DateUtils.getNowDate());
        SqlResult result = updateSQLModel(wmItemRecptLine);
        return result;
    }


    private static Lock lock = new ReentrantLock();
    /**
     * 排产任务产品入库  关联 排产任务,和预出库 逻辑
     * @param wmItemRecptLine
     * @param canNullTask
     * @return
     */
    public SqlResult inPutRelationProstaskAndWillOut(WmItemRecptLine wmItemRecptLine,ProTask canNullTask){

        //查询排产总量， 非当前客户需求，其他客户需求的预出库的总量，非当前入库记录的已入库总量
        List<JSONObject> list = wmItemRecptLineService.findTaskQuantityAndItemRecptLineQuantity(wmItemRecptLine);
        float thisCount = wmItemRecptLine.getQuantityRecived().floatValue();

        int addCount = 20;
        if (list != null && list.size() > 0){
            JSONObject jsonObject = list.get(0);

            float taskQuantity = jsonObject.getFloatValue("taskquantity");

            //非当前记录的已入库总量
            float inquantity = jsonObject.getFloatValue("inquantity");

            if (taskQuantity +addCount < inquantity + thisCount){
                return SqlResult.error("入库数量不应该大于排产数量+"+addCount+"kg",null);
            }

            //非当前客户需求，其他客户需求的预出库的总量
            float otherWillCount = jsonObject.getFloatValue("allwilloutquantity"); //其他产品预出总量

            if (thisCount+otherWillCount+inquantity > taskQuantity+addCount){
                return SqlResult.error("当前产品入库数量过大，会导致此排产任务的其他产品的预出库数量无法满足",null);
            }
        }else {

            if (canNullTask.getQuantity().floatValue() + addCount < thisCount){
                return SqlResult.error("入库数量不应该大于排产数量+"+addCount+"kg",null);
            }
        }

        return SqlResult.ok("",null);
    }



    /**
     * 更新产品入库的出库数量
     * @param lineId
     */
    public void updateItemRecptLineOutQuantity(Long lineId){
        getBaseMapper().updateItemRecptLineOutQuantity(lineId);
    }

    @Override
    public IPage<WmItemRecptLine> findList(Page page, WmItemRecptLine wmItemRecptLine) {
        return getBaseMapper().findList(page,wmItemRecptLine);
    }

    /**
     * 同步库存
     */
    public synchronized void sysnStock(){
        NoticeWebsocket.sendMessage(NoticeWbsocketType.SyncT6,"T6 库存开始，执行T6库存统计");
        fromService.updateSql("exec SP_ClearCurrentStock_ST;");
        NoticeWebsocket.sendMessage(NoticeWbsocketType.SyncT6,"删除本地入库数据");
        getBaseMapper().deleteItemRecptLine();
        NoticeWebsocket.sendMessage(NoticeWbsocketType.SyncT6,"开始统计获取T6入库信息");
        SyncModel syncModel = new SyncModel();
        syncModel.setService(fromService,toIService);

        String tableName = "(SELECT\n" +
                "\tMAX(AutoID) as AutoID,cInvCode,cBatch,cWhCode,cWhName,cBarCode,cInvName,cInvStd,cInvDefine1,cInvDefine2,cInvDefine3,SUM (quantity) AS iQuantity\n" +
                "FROM\n" +
                "\t(\n" +
                "\tSELECT\n" +
                "\t\tAutoID,\n" +
                "\t\tCurrentStock.cBatch,\n" +
                "\t\tCurrentStock.cWhCode,\n" +
                "\t\tcWhName,\n" +
                "\t\tWarehouse.cBarCode,\n" +
                "\t\tCurrentStock.cInvCode,\n" +
                "\t\tcInvName,\n" +
                "\t\tcInvStd,\n" +
                "\t\tcInvDefine1,\n" +
                "\t\tcInvDefine2,\n" +
                "\t\tcInvDefine3,\n" +
                "\t\t(iQuantity + fOutQuantity + fInQuantity) AS quantity \n" +
                "\tFROM\n" +
                "\t\tCurrentStock\n" +
                "\t\tLEFT JOIN Inventory ON CurrentStock.cInvCode = Inventory.cInvCode\n" +
                "\t\tLEFT JOIN Warehouse ON CurrentStock.cWhCode = Warehouse.cWhCode\n" +
                "\t) P where quantity > 0 GROUP BY cInvCode,cBatch,cWhCode,cWhName,cBarCode,cInvName,cInvStd,cInvDefine1,cInvDefine2,cInvDefine3)P";

        syncModel.setTable(tableName,"wm_item_recpt_line");

        syncModel.setSyncData("AutoID",null,"line_id",null);

        syncModel.addColumn("AutoID","line_id",SyncModel.SyncModelType.TypeString);
        syncModel.addColumn("cBatch","batch_code", SyncModel.SyncModelType.TypeString);
        syncModel.addColumn("cWhCode","warehouse_id", SyncModel.SyncModelType.TypeString);
        syncModel.addColumn("cBarCode","warehouse_code", SyncModel.SyncModelType.TypeString);
        syncModel.addColumn("cWhName","warehouse_name", SyncModel.SyncModelType.TypeString);

        syncModel.addColumn("cInvCode","item_code", SyncModel.SyncModelType.TypeString);
        syncModel.addColumn("cInvName","item_name", SyncModel.SyncModelType.TypeString);
        syncModel.addColumn("cInvStd","specification", SyncModel.SyncModelType.TypeString);
        syncModel.addColumn("cInvDefine1","viscosity", SyncModel.SyncModelType.TypeString);
        syncModel.addColumn("cInvDefine2","tag", SyncModel.SyncModelType.TypeString);
        syncModel.addColumn("cInvDefine3","packing_type", SyncModel.SyncModelType.TypeString);

        syncModel.addColumn("iQuantity","quantity_recived", SyncModel.SyncModelType.TypeString);
        syncModel.addColumn("iQuantity","quantity", SyncModel.SyncModelType.TypeString);
        syncModel.putDefaultValue("in_type","5");
        syncModel.putDefaultValue("is_in_stock",1);
        syncModel.putDefaultValue("quantity_out","0");
        syncModel.synsStart("入库信息");
        getBaseMapper().updateProductItemId();
        NoticeWebsocket.sendMessage(NoticeWbsocketType.SyncT6,"开始统计获取T6库存信息");
        wmMaterialStockService.sysnStock();
        NoticeWebsocket.sendMessage(NoticeWbsocketType.SyncT6,"T6库存信息同步完成");

    }

    @Override
    public WmItemRecptLine findOld(WmItemRecptLine model) {
        WmItemRecptLine item = getById(model.getLineId());
        return item;
    }

    @Override
    public List<WmItemRecptLine> getFromIds(Serializable[] ids) {
        QueryWrapper<WmItemRecptLine> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("line_id",ids);
        return list(queryWrapper);
    }

    //监听领料,出库
//    @SQLListenerInterface(tableName = "wm_issue_line",listerType = {SQLListenerType.AddBefore,SQLListenerType.ChangeBefore,SQLListenerType.DeleteBefore})
    public SqlResult wmIssueLineListener(SQLListenerType type,WmIssueLine oldObj,WmIssueLine newObj) {
        //统计出库
        try {
            WmItemRecptLine itemRecptLine = getById(newObj == null? oldObj.getItemRecptLineId():newObj.getItemRecptLineId());
            if (itemRecptLine == null){
                return SqlResult.error("拆分领料的入库记录不存在",newObj);
            }
            float oldCount = 0;
            float newCount = 0;
            if (oldObj != null && oldObj.getIsInStock().equals("1")){
                oldCount = oldObj.getQuantity().floatValue();
            }
            if (newObj != null&& newObj.getIsInStock().equals("1")){
                newCount = newObj.getQuantity().floatValue();
            }
            if (type == SQLListenerType.AddBefore
                    || type == SQLListenerType.ChangeBefore
                    || type == SQLListenerType.DeleteBefore){

                //预出库不影响库存
                if (oldCount == 0 && newCount == 0){
                    return SqlResult.ok(null,null);
                }

                if (oldObj != null && newObj != null && !oldObj.getItemCode().equals(newObj.getItemCode())){
                    return SqlResult.error("领料记录不能修改产品",newObj);
                }

                //增加，编辑是判断数量
                if ( itemRecptLine.getQuantity().floatValue() < newCount - oldCount){
                    return SqlResult.error("领料数量大于当前入库记录库存",newObj);
                }

                float ss =  newCount - oldCount;
                if (itemRecptLine.getQuantityOut() != null){
                    ss += itemRecptLine.getQuantityOut().doubleValue();
                }
                itemRecptLine.setQuantityOut(BigDecimal.valueOf(ss));

                //修改剩余量
                float shengYu = itemRecptLine.getQuantityRecived().floatValue() - itemRecptLine.getQuantityOut().floatValue();
                itemRecptLine.setQuantity(BigDecimal.valueOf(shengYu));

                //更新并通知
                return  updateSQLModel(itemRecptLine);
            }
        }catch (Exception e){
            e.printStackTrace();
            return SqlResult.error(this.getClass().toString(),e);
        }
        return SqlResult.ok(null,newObj);
    }


    @SQLListenerInterface(tableName = "wm_issue_line",listerType = {SQLListenerType.AddBefore,SQLListenerType.ChangeBefore})
    public SqlResult wmIssueLineListener2(SQLListenerType type,WmIssueLine oldObj,WmIssueLine newObj){
        try {
            InventoryClassContent content = new InventoryClassContent();
            JSONObject o = new JSONObject();
            o.put("Code",newObj.getItemCode());
            List list = new ArrayList<>();
            list.add(o);
            cn.hutool.json.JSONObject inventory = new cn.hutool.json.JSONObject();
            inventory.put("Inventory",list);
            content.setParam(inventory);
            InventoryClassResponse response = chanjetSpi.getStockList(content);
            List<Map> data = response.getData();
            if(data.size() == 0){
                return SqlResult.error("物料产品查询无库存记录",newObj);
            }
            List<Map> stockList = data.stream().filter(map -> {
                Long id = new BigDecimal((String) map.get("InventoryID") + (String) map.get("WarehouseID")).longValue();
                if (id == newObj.getMaterialStockId().longValue()){
                    return true;
                }
                return false;
            }).collect(Collectors.toList());
            if(stockList.size() > 1){
                return SqlResult.error("出库失败，物料重复",newObj);
            }
            float allCount = 0;
//            float oldCount = 0;
            float receiveCount = 0;
            Map map = stockList.get(0);
            allCount = new BigDecimal((String)map.get("ExistingQuantity")).floatValue();
            receiveCount = newObj.getQuantity().floatValue();
            if (type == SQLListenerType.AddBefore
                    || type == SQLListenerType.ChangeBefore
                    || type == SQLListenerType.DeleteBefore){

                //预出库不影响库存
                if (allCount == 0 && receiveCount == 0){
                    return SqlResult.ok(null,null);
                }

                if (oldObj != null && newObj != null && !oldObj.getItemCode().equals(newObj.getItemCode())){
                    return SqlResult.error("领料记录不能修改产品",newObj);
                }

                //增加，编辑是判断数量
                if (allCount < receiveCount){
                    return SqlResult.error("领料数量大于当前入库记录库存",newObj);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            return SqlResult.error(this.getClass().toString(),e);
        }
        return SqlResult.ok(null,newObj);
    }
}
